import os
import tkinter as tk
import threading
from tkinter import ttk, filedialog, messagebox, scrolledtext
from pathlib import Path
import queue
import time

class FilterRule:
    """过滤规则类，用于存储单条过滤规则"""
    def __init__(self):
        self.logic = tk.StringVar(value="包含")  # 包含/不包含
        self.text = tk.StringVar()              # 过滤文本

class CommentSplitterApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("评价拆分工具")
        self.geometry("600x600")
        self.minsize(500, 550)
        
        # 线程相关变量
        self.split_thread = None
        self.stop_event = threading.Event()
        self.queue = queue.Queue()  # 用于线程间通信
        
        # 样式配置
        self.style = ttk.Style()
        self.style.configure("TButton", font=("微软雅黑", 9))
        self.style.configure("TLabel", font=("微软雅黑", 9))
        self.style.configure("Header.TLabel", font=("微软雅黑", 11, "bold"))
        self.style.configure("FilterLabel.TLabel", font=("微软雅黑", 8, "italic"), foreground="#888")

        # 核心变量
        self.comment_path = tk.StringVar()
        self.output_path = tk.StringVar()
        self.comments = []
        self.filtered_comments = []
        self.filter_rules = [FilterRule()]
        
        self.init_ui()
        self.check_queue()  # 启动队列检查
        
    def init_ui(self):
        """初始化界面"""
        main_frame = ttk.Frame(self, padding=10)
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 标题
        ttk.Label(
            main_frame, 
            text="评价拆分工具", 
            style="Header.TLabel"
        ).grid(row=0, column=0, columnspan=2, pady=(0, 10), sticky=tk.W)

        # 输入区域
        ttk.Label(main_frame, text="评价文件:").grid(row=1, column=0, sticky=tk.W, pady=2)
        ttk.Entry(main_frame, textvariable=self.comment_path, width=25).grid(row=1, column=1, pady=2, padx=5, sticky=tk.EW)
        ttk.Button(
            main_frame, 
            text="浏览", 
            command=self.select_comment_file,
            width=5
        ).grid(row=1, column=2, pady=2, padx=5, sticky=tk.W)

        ttk.Label(main_frame, text="输出目录:").grid(row=2, column=0, sticky=tk.W, pady=2)
        ttk.Entry(main_frame, textvariable=self.output_path, width=25).grid(row=2, column=1, pady=2, padx=5, sticky=tk.EW)
        ttk.Button(
            main_frame, 
            text="浏览", 
            command=self.select_output_path,
            width=5
        ).grid(row=2, column=2, pady=2, padx=5, sticky=tk.W)

        main_frame.grid_columnconfigure(1, weight=1)

        # 过滤规则区域
        filter_frame = ttk.LabelFrame(main_frame, text="过滤规则", padding=10)
        filter_frame.grid(row=3, column=0, columnspan=3, pady=10, sticky=tk.EW)

        # 规则标题行
        ttk.Label(filter_frame, text="序号", font=("微软雅黑", 9, "bold")).grid(row=0, column=0, padx=2, pady=2)
        ttk.Label(filter_frame, text="类型", font=("微软雅黑", 9, "bold")).grid(row=0, column=1, padx=2, pady=2)
        ttk.Label(filter_frame, text="关键词", font=("微软雅黑", 9, "bold")).grid(row=0, column=2, padx=2, pady=2)
        ttk.Label(filter_frame, text="操作", font=("微软雅黑", 9, "bold")).grid(row=0, column=3, padx=2, pady=2)

        self.update_filter_rows(filter_frame)

        # 按钮区
        btn_frame = ttk.Frame(filter_frame)
        btn_frame.grid(row=100, column=0, columnspan=4, pady=5, sticky=tk.EW)

        ttk.Button(
            btn_frame, 
            text="添加规则", 
            command=lambda: self.add_filter_rule(filter_frame),
            width=6
        ).pack(side=tk.LEFT, padx=2)

        ttk.Button(
            filter_frame, 
            text="应用过滤", 
            command=self.apply_filter,
            width=6
        ).grid(row=101, column=0, columnspan=4, pady=5, sticky=tk.E)

        # 说明文字
        ttk.Label(
            filter_frame, 
            text="说明：所有规则需同时满足（逻辑与）。如规则1选“包含A”、规则2选“不包含B”，则保留同时符合的评价",
            style="FilterLabel.TLabel",
            wraplength=400
        ).grid(row=102, column=0, columnspan=4, pady=2, sticky=tk.W)

        filter_frame.grid_columnconfigure(2, weight=1)

        # 预览区域
        preview_frame = ttk.LabelFrame(main_frame, text="评价预览", padding=10)
        preview_frame.grid(row=4, column=0, columnspan=3, pady=5, sticky=tk.EW)

        self.preview_text = scrolledtext.ScrolledText(
            preview_frame, 
            wrap=tk.WORD, 
            height=8
        )
        self.preview_text.pack(fill=tk.BOTH, expand=True)
        self.preview_text.config(state=tk.DISABLED)

        # 状态与操作
        self.status_label = ttk.Label(main_frame, text="就绪", foreground="blue", font=("微软雅黑", 9))
        self.status_label.grid(row=5, column=0, columnspan=3, sticky=tk.W, pady=2)

        btn_frame_main = ttk.Frame(main_frame)
        btn_frame_main.grid(row=6, column=0, columnspan=3, pady=5, sticky=tk.EW)

        ttk.Button(
            btn_frame_main, 
            text="加载评价", 
            command=self.load_comments,
            width=6
        ).pack(side=tk.LEFT, padx=2)

        self.split_btn = ttk.Button(
            btn_frame_main, 
            text="拆分评价", 
            command=self.start_split_thread,
            width=6
        )
        self.split_btn.pack(side=tk.RIGHT, padx=2)

        self.cancel_btn = ttk.Button(
            btn_frame_main, 
            text="取消", 
            command=self.cancel_split,
            width=6,
            state=tk.DISABLED
        )
        self.cancel_btn.pack(side=tk.RIGHT, padx=2)

    # 过滤规则管理
    def update_filter_rows(self, parent_frame):
        """更新过滤规则行显示"""
        for widget in parent_frame.winfo_children():
            grid_info = widget.grid_info()
            if 0 < grid_info.get("row", 0) < 100:
                widget.destroy()

        for i, rule in enumerate(self.filter_rules, 1):
            ttk.Label(parent_frame, text=str(i), font=("微软雅黑", 9)).grid(row=i, column=0, padx=2, pady=2)
            
            ttk.Combobox(
                parent_frame, 
                textvariable=rule.logic, 
                values=["包含", "不包含"],
                state="readonly",
                width=4
            ).grid(row=i, column=1, padx=2, pady=2)
            
            ttk.Entry(
                parent_frame, 
                textvariable=rule.text, 
                width=15
            ).grid(row=i, column=2, padx=2, pady=2, sticky=tk.EW)
            
            btn_state = "normal" if len(self.filter_rules) > 1 else "disabled"
            ttk.Button(
                parent_frame, 
                text="删除", 
                command=lambda idx=i-1: self.remove_filter_rule(idx, parent_frame),
                state=btn_state,
                width=4
            ).grid(row=i, column=3, padx=2, pady=2)

    def add_filter_rule(self, parent_frame):
        """添加一条新的过滤规则"""
        self.filter_rules.append(FilterRule())
        self.update_filter_rows(parent_frame)

    def remove_filter_rule(self, index, parent_frame):
        """删除一条过滤规则"""
        if len(self.filter_rules) > 1:
            del self.filter_rules[index]
            self.update_filter_rows(parent_frame)

    # 基础功能
    def select_comment_file(self):
        """选择评价文件"""
        file_path = filedialog.askopenfilename(
            title="选择评价文件",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if file_path:
            self.comment_path.set(file_path)

    def select_output_path(self):
        """选择输出目录"""
        dir_path = filedialog.askdirectory(
            title="选择输出目录",
            initialdir=os.path.expanduser("~")
        )
        if dir_path:
            self.output_path.set(dir_path)

    def load_comments(self):
        """加载评价文件"""
        file_path = self.comment_path.get()
        if not file_path or not os.path.exists(file_path):
            messagebox.showerror("错误", "请选择有效文件！")
            return

        try:
            with open(file_path, "r", encoding="utf-8") as f:
                self.comments = [line.strip() for line in f if line.strip()]

            self.filtered_comments = self.comments.copy()
            self.update_preview()
            self.status_label.config(text=f"已加载 {len(self.comments)} 条评价")
            messagebox.showinfo("成功", f"加载 {len(self.comments)} 条评价！")
        except Exception as e:
            messagebox.showerror("错误", f"加载失败：{str(e)}")
            self.status_label.config(text="加载失败")

    # 过滤逻辑
    def apply_filter(self):
        """应用多条件过滤"""
        if not self.comments:
            messagebox.showwarning("提示", "请先加载评价文件！")
            return

        valid_rules = []
        for rule in self.filter_rules:
            text = rule.text.get().strip()
            if text:
                valid_rules.append({
                    "logic": rule.logic.get(),
                    "text": text
                })

        if not valid_rules:
            self.filtered_comments = self.comments.copy()
            self.status_label.config(text="无有效规则，显示全部评价")
            self.update_preview()
            return

        self.filtered_comments = []
        for comment in self.comments:
            match_all = True
            for rule in valid_rules:
                if rule["logic"] == "包含":
                    if rule["text"] not in comment:
                        match_all = False
                        break
                else:
                    if rule["text"] in comment:
                        match_all = False
                        break
            if match_all:
                self.filtered_comments.append(comment)

        rule_desc = "; ".join([f"{r['logic']}{r['text']}" for r in valid_rules])
        self.status_label.config(
            text=f"过滤完成！共 {len(self.filtered_comments)} 条符合条件的评价（规则：{rule_desc}）"
        )
        self.update_preview()

    def update_preview(self):
        """更新预览区"""
        self.preview_text.config(state=tk.NORMAL)
        self.preview_text.delete(1.0, tk.END)

        display_limit = 10
        for i, comment in enumerate(self.filtered_comments[:display_limit], 1):
            self.preview_text.insert(tk.END, f"{i}. {comment}\n\n")

        if len(self.filtered_comments) > display_limit:
            self.preview_text.insert(tk.END, f"... 还有 {len(self.filtered_comments)-display_limit} 条未显示 ...\n")

        self.preview_text.config(state=tk.DISABLED)

    # 多线程拆分功能
    def start_split_thread(self):
        """启动拆分线程"""
        output_dir = self.output_path.get()
        if not output_dir:
            messagebox.showerror("错误", "请选择输出目录！")
            return

        if not self.filtered_comments:
            messagebox.showerror("错误", "无有效评价可拆分！")
            return

        # 检查是否已有线程在运行
        if self.split_thread and self.split_thread.is_alive():
            messagebox.showinfo("提示", "拆分正在进行中，请等待完成或取消当前操作")
            return

        # 初始化线程相关变量
        self.stop_event.clear()
        self.split_thread = threading.Thread(
            target=self.split_comments_thread,
            args=(output_dir, self.filtered_comments.copy())
        )
        
        # 更新UI状态
        self.split_btn.config(state=tk.DISABLED)
        self.cancel_btn.config(state=tk.NORMAL)
        self.status_label.config(text="准备开始拆分...")
        self.preview_text.config(state=tk.NORMAL)
        self.preview_text.delete(1.0, tk.END)
        self.preview_text.config(state=tk.DISABLED)
        
        # 启动线程
        self.split_thread.start()

    def split_comments_thread(self, output_dir, comments_to_split):
        """在后台线程中执行拆分操作"""
        try:
            main_dir = Path(output_dir).joinpath("评价文本集合")
            main_dir.mkdir(parents=True, exist_ok=True)
            
            total = len(comments_to_split)
            
            for idx, comment in enumerate(comments_to_split, 1):
                # 检查是否需要停止
                if self.stop_event.is_set():
                    self.queue.put(("cancel", None))
                    return
                
                # 执行拆分操作
                sub_dir = main_dir.joinpath(f"评价_{idx:03d}")
                sub_dir.mkdir(exist_ok=True)
                
                with open(sub_dir.joinpath("comment.txt"), "w", encoding="utf-8") as f:
                    f.write(comment)
                
                # 发送进度更新到主线程
                self.queue.put((
                    "progress", 
                    {
                        "idx": idx, 
                        "total": total,
                        "comment": comment,
                        "main_dir": main_dir
                    }
                ))
                
                # 短暂休眠，减少CPU占用
                time.sleep(0.01)
            
            # 发送完成信号
            self.queue.put(("complete", {"total": total, "main_dir": main_dir}))
            
        except Exception as e:
            self.queue.put(("error", str(e)))

    def cancel_split(self):
        """取消当前拆分操作"""
        if self.split_thread and self.split_thread.is_alive():
            self.stop_event.set()
            self.status_label.config(text="正在取消...")
            self.cancel_btn.config(state=tk.DISABLED)

    def check_queue(self):
        """检查消息队列，更新UI（在主线程中执行）"""
        while not self.queue.empty():
            message_type, data = self.queue.get()
            
            if message_type == "progress":
                # 更新进度
                self.status_label.config(text=f"正在拆分：{data['idx']}/{data['total']}")
                self.preview_text.config(state=tk.NORMAL)
                self.preview_text.insert(tk.END, f"已保存：评价_{data['idx']:03d}\n{data['comment'][:30]}...\n\n")
                self.preview_text.see(tk.END)
                self.preview_text.config(state=tk.DISABLED)
                
            elif message_type == "complete":
                # 处理完成
                self.status_label.config(text=f"拆分完成！共生成 {data['total']} 个文件夹")
                self.split_btn.config(state=tk.NORMAL)
                self.cancel_btn.config(state=tk.DISABLED)
                messagebox.showinfo("成功", f"已拆分至：\n{data['main_dir']}\n共 {data['total']} 条评价")
                
            elif message_type == "cancel":
                # 已取消
                self.status_label.config(text="拆分已取消")
                self.split_btn.config(state=tk.NORMAL)
                self.cancel_btn.config(state=tk.DISABLED)
                messagebox.showinfo("提示", "拆分操作已取消")
                
            elif message_type == "error":
                # 处理错误
                self.status_label.config(text="拆分失败")
                self.split_btn.config(state=tk.NORMAL)
                self.cancel_btn.config(state=tk.DISABLED)
                messagebox.showerror("错误", f"拆分失败：{data}")
        
        # 继续检查队列（每100毫秒）
        self.after(100, self.check_queue)

    def on_closing(self):
        """窗口关闭时的处理"""
        if self.split_thread and self.split_thread.is_alive():
            if messagebox.askyesno("提示", "拆分正在进行中，确定要关闭窗口吗？"):
                self.stop_event.set()
                self.destroy()
        else:
            self.destroy()

if __name__ == "__main__":
    app = CommentSplitterApp()
    app.protocol("WM_DELETE_WINDOW", app.on_closing)  # 设置窗口关闭事件处理
    app.mainloop()
    